package com.ruiben.mall.intercepter;

import com.ruiben.mall.LoginRequired;
import com.ruiben.mall.impl.AdminServiceImpl;
import com.ruiben.mall.impl.UserServiceImpl;
import com.ruiben.mall.pojo.Admin;
import com.ruiben.mall.pojo.User;
import com.ruiben.mall.utils.CommonJSONResult;
import com.ruiben.mall.utils.JsonUtils;
import com.ruiben.mall.utils.RedisOperator;
import com.ruiben.mall.utils.TokenUtils;
import io.jsonwebtoken.Claims;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import tk.mybatis.mapper.entity.Example;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;

import static com.ruiben.mall.controller.BaseController.USER_REDIS_SESSION;

public class AdminAuthInterceptor implements HandlerInterceptor {
    public final static String ACCESS_TOKEN = "token";
    @Autowired
    private UserServiceImpl userService;

    @Autowired
    private RedisOperator redis;

    /**
     * 在请求处理之前进行调用（Controller方法调用之前）
     *
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 如果不是映射到方法直接通过
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
        // 判断接口是否需要登录
        LoginRequired methodAnnotation = method.getAnnotation(LoginRequired.class);
        // 有 @LoginRequired 注解，需要认证
        if (methodAnnotation != null) {
            // 判断是否存在令牌信息，如果存在，则允许登录
//            String accessToken = request.getParameter(ACCESS_TOKEN);
            String accessToken = request.getHeader("token");
            if (null == accessToken) {
                returnErrorResponse(response,CommonJSONResult.errorException("无token，请重新登录"));
                return false;
            }
            Claims claims = null;
            try {
                claims = TokenUtils.parseJWT(accessToken);
                if (claims==null){
                    returnErrorResponse(response,CommonJSONResult.errorException("token不正确，请重新登录"));
                    return false;
                }
            } catch (Exception e) {
                returnErrorResponse(response,CommonJSONResult.errorException("token不正确，请重新登录"));
                return false;
            }
            String userId = claims.getId();
            User user = userService.queryUserInfoById(userId);
            if (user == null) {
                returnErrorResponse(response,CommonJSONResult.errorException("用户不存在"));
                return false;
            }


            String s = redis.get(USER_REDIS_SESSION + ":" + user.getId());
            if (StringUtils.isBlank(s) || !accessToken.equals(s)) {
                returnErrorResponse(response,CommonJSONResult.errorException("token过期，请重新登录"));
                return false;
            }

            return true;
        }
        return true;
    }

    /**
     * 请求处理之后进行调用，但是在视图被渲染之前（Controller方法调用之后）
     *
     * @param httpServletRequest
     * @param httpServletResponse
     * @param o
     * @param modelAndView
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {

    }

    /**
     * 在整个请求结束之后被调用，也就是在DispatcherServlet 渲染了对应的视图之后执行（主要是用于进行资源清理工作）
     *
     * @param httpServletRequest
     * @param httpServletResponse
     * @param o
     * @param e
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {

    }


    public void returnErrorResponse(HttpServletResponse response, CommonJSONResult result)
            throws IOException {
        OutputStream out=null;
        try{
            response.setCharacterEncoding("utf-8");
            response.setContentType("text/json");
            out = response.getOutputStream();
            out.write(JsonUtils.objectToJson(result).getBytes("utf-8"));
            out.flush();
        } finally{
            if(out!=null){
                out.close();
            }
        }
    }
}
